package com.tarena.lbs.article.web.service;

import com.sun.xml.internal.bind.v2.TODO;
import com.tarena.lbs.article.web.repository.ArticleRepository;
import com.tarena.lbs.article.web.utils.AuthenticationContextUtils;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.common.content.utils.SequenceGenerator;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.marketing.api.MarketingApi;
import com.tarena.lbs.pojo.content.entity.ActionSearchEntity;
import com.tarena.lbs.pojo.content.entity.ArticleSearchEntity;
import com.tarena.lbs.pojo.content.param.ArticleActionParam;
import com.tarena.lbs.pojo.content.param.ArticleContentParam;
import com.tarena.lbs.pojo.content.query.ArticleQuery;
import com.tarena.lbs.pojo.content.vo.ArticleActionPageResultVO;
import com.tarena.lbs.pojo.content.vo.ArticleActionVO;
import com.tarena.lbs.pojo.content.vo.ArticleVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ArticleService {
    @Autowired
    private ArticleRepository articleRepository;
    @DubboReference
    private MarketingApi marketingApi;
    public PageResult<ArticleVO> articleList(ArticleQuery query) throws BusinessException {
        //1.准备一个返回值,将分页查询简化
        PageResult<ArticleVO> voPage=initPageResult(1,10,100l);//初始化一个假的分页数据 pageNo=1 pageSize=10 total=100L
        //2.基于入参中的source值 准备2个不同的仓储层查询条件
        ArticleQuery repoQuery=new ArticleQuery();
        Integer source = query.getSource();
        Asserts.isTrue(source==null,new BusinessException("-2","非法的查询文章来源"));
        //3.判断来源
        if(source==1){
            //前台条件封装
            //latitude longitude articleLabel articleStatus=1
            repoQuery.setLatitude(query.getLatitude());
            repoQuery.setLongitude(query.getLongitude());
            repoQuery.setArticleLabel(query.getArticleLabel());
            ArrayList<Integer> status=new ArrayList<>();
            status.add(1);
            repoQuery.setArticleStatus(status);
        }else{
            //source==2 分页查询来自于后台 articleTitle,articleCategoryId,articleStatus,source=2,activityId,updateStartTime,updateEndTime,userId
            BeanUtils.copyProperties(query,repoQuery);
            //如果直接查询 会查询到 所有满足 默认条件source=2 status=1|0 文章
            //后台查询 只查询当前请求所属用户的文章比如海底捞管理员 只查询海底捞管理员创建的文章
            Integer userId=getUserId();
            repoQuery.setUserId(userId);
        }
        //4.调用仓储层 RestHighLevelClient拼接不同非空属性的搜索query 放到bool复合查询
        List<ArticleSearchEntity> entities= articleRepository.searchArticles(repoQuery);
        //5.转化vo封装voPage的objects属性 但是只有在entities非空
        if (entities!=null&&entities.size()>0){
            voPage.setObjects(entities.stream().map(
                    entity->{
                        ArticleVO vo=new ArticleVO();
                        BeanUtils.copyProperties(entity,vo);
                        return vo;
                    }
            ).collect(Collectors.toList()));
        }
        return voPage;
    }

    private Integer getUserId() throws BusinessException {
        UserPrinciple userPrinciple = AuthenticationContextUtils.get();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","认证解析失败"));
        return userPrinciple.getId();
    }

    private PageResult<ArticleVO> initPageResult(int pageNo, int pageSize, long total) {
        PageResult<ArticleVO> page=new PageResult<>(pageSize,pageNo);
        page.setTotal(total);
        return page;
    }

    public void addArticle(ArticleContentParam param) throws BusinessException {
        //1.封装entity对象数据,交给仓储层新增
        ArticleSearchEntity entity=assembleArticleEntity(param);
        articleRepository.save(entity);
        //2.绑定图片 封面cover 500 内容 600
        bindArticlePics(param,entity.getId());
    }

    private ArticleSearchEntity assembleArticleEntity(ArticleContentParam param) throws BusinessException {
        ArticleSearchEntity entity=new ArticleSearchEntity();
        BeanUtils.copyProperties(param,entity);
        //1.文档id
        entity.setId(SequenceGenerator.sequence());
        //2.缺少作者
        UserPrinciple userPrinciple = AuthenticationContextUtils.get();
        entity.setUserId(userPrinciple.getId());
        entity.setArticleUsername(userPrinciple.getNickname());
        //3.地理位置lat 39.90909 lon 116.12321312 39.9090,116.1119321
        entity.setLocation(param.getLatitude()+","+param.getLongitude());
        //4.文章点赞 收藏 访问次数 后续放到redis中实现的,没有使用es
        entity.setAccessCount(0);
        entity.setFavoriteCount(0);
        entity.setLikeCount(0);
        //5.时间
        Date now=new Date();
        entity.setCreateTime(now);
        entity.setUpdateTime(now);
        log.info("新增穿件文章入参:{},封装文章entity:{}",param,entity);
        return entity;
    }

    private void bindArticlePics(ArticleContentParam param, Integer id) {
        //TODO
    }

    public Set<String> getArticleLabels(ArticleQuery query) {
        //lat lon source(来源是1 前台) status=1
        //让仓储层 给我查询的是根据label去重之后的entities 在业务层解析hashSet
        List<ArticleSearchEntity> entities=articleRepository.getArticleLabels(query);
        //从entities解析 提取标签集合
        Set<String> labels=null;
        if(entities!=null&&entities.size()>0){
            labels=entities.stream().map(entity->{
                return entity.getArticleLabel();
            }).collect(Collectors.toSet());
        }
        return labels;
    }

    public ArticleVO articleDetail(Integer id) throws BusinessException {
        //1.拿到登录用户id
        Integer userId=getUserId();
        //1.5 对文章做更新的操作 accessCount+1 behave 1 like 2 favor 3
        articleRepository.updateCountandSaveAction(id,3,1,userId);
        //1.6 记录userAction用户行为 谁 对哪篇文章 做了何种操作
        //2.查看文章详情
        ArticleSearchEntity entity=articleRepository.getArticleById(id);
        //3.看文章的activityId是否非空
        if (entity.getActivityId()!=null){
            //4.远程调用marketing 得到一个反馈 带不带这个活动id
            boolean visible = marketingApi.activityIsVisible(userId, entity.getActivityId());
            //5.如果不带 entity.setActivityId(null)
            if (!visible){
                log.info("当前用户:{},不属于目标人群,不携带活动:{}",
                        userId,entity.getActivityId());
                entity.setActivityId(null);
            }
        }
        //本次查询 对文章中 的数据 accessCount++1 entity 详情能够获取accessCount
        //6.封装VO返回
        ArticleVO vo=null;
        if (entity!=null){
            vo=new ArticleVO();
            BeanUtils.copyProperties(entity,vo);
        }
        return vo;
    }

    public void userBehave(ArticleActionParam param) throws BusinessException {
        //1.解析用户userId
        Integer userId = getUserId();
        //2.调用在详情查询接口 实现的功能
        articleRepository.updateCountandSaveAction(param.getId(),param.getBehavior(),1,userId);
    }

    public ArticleActionPageResultVO getBehaviorList(ArticleQuery query) throws BusinessException {
        //1.获取userId
        Integer userId = getUserId();
        //2.查询用户点赞的文章列表 封装点赞的分页数据
        PageResult<ArticleActionVO> likeVo=selectBehaveArticles(userId,1);
        PageResult<ArticleActionVO> favorVo=selectBehaveArticles(userId,2);
        PageResult<ArticleActionVO> accessVo=selectBehaveArticles(userId,3);
        //3.封装vo返回数据
        ArticleActionPageResultVO vo=new ArticleActionPageResultVO();
        vo.setLikeFuturePageResult(likeVo);
        vo.setCollectFutureOPageResult(favorVo);
        vo.setCommentFuturePageResult(accessVo);
        return vo;
    }

    private PageResult<ArticleActionVO> selectBehaveArticles(Integer userId, Integer behave) {
        //1.调用仓储层 封装查询条件 查询行为记录 之后将articleActionVO使用articleId去重
        List<ActionSearchEntity> entities=articleRepository.selectActionArticles(userId,behave);
        //2.封装page
        PageResult<ArticleActionVO> voPage=new PageResult<>(10,1);
        voPage.setTotal(100l);
        //3.list
        List<ArticleActionVO> vos=null;
        if (entities!=null&&entities.size()>0){
            vos=entities.stream().map(entity->{
                ArticleActionVO vo=new ArticleActionVO();
                BeanUtils.copyProperties(entity,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        voPage.setObjects(vos);
        return voPage;
    }
}
